// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: linchuan

#pragma once

#include <cstdio>
#include <map>
#include <memory>
#include <string>
#include <vector>

#include <rapidjson/document.h>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/bitstamp/symbology/currency.h"
#include "coin2/exchange/bitstamp/symbology/product.h"

namespace FIX {
class Message;
}

namespace coin2::exchange::bitstamp::order_v2 {

constexpr auto MSG_TYPE_SESSION_REJECT = "3";
constexpr auto MSG_TYPE_EXECUTION_REPORT = "8";
constexpr auto MSG_TYPE_CANCEL_REJECT = "9";
constexpr auto MSG_TYPE_BUSINESS_REJECT = "j";
constexpr auto EXEC_TYPE_NEW_ORDER = '0';
constexpr auto EXEC_TYPE_ORDER_CANCELLED = '4';
constexpr auto EXEC_TYPE_ORDER_REJECTED = '8';
constexpr auto EXEC_TYPE_ORDER_FILL = 'F';
constexpr auto ORD_STATUS_NEW_ORDER = '0';
constexpr auto ORD_STATUS_PARTIALLY_FILLED = '1';
constexpr auto ORD_STATUS_FULLY_FILLED = '2';
constexpr auto ORD_STATUS_CANCELLED = '4';
constexpr auto ORD_STATUS_REJECTED = '8';

class BitstampParser : public base::order::BaseParser {
 public:
  const ParseResult& ParseRawMessage(const RawMessage& msg) override;
  AccountBalance ParseBalance(const JsonValue& doc) override;
  bool ParseRawBalance(const JsonValue& doc, RawBalanceMap* raw_balance_map);

 private:
  void ParseSubmitResponse();
  void ParseCancelResponse();
  void ParseRestOpensInfo();
  void ParseRestFillInfoList();
  void ParseRestAccountBalance();
  void ParseWsMessage();
  void ParseFixMessage();

  ProductOrderBundle ParseWsOrderInfoListV2(const JsonValue& data);
  ProductFillBundle ParseWsFillInfoListV2(const JsonValue& data);
  coin::proto::ProductOrderElement ParseOrderInfo(const JsonValue& data);
  const std::string& GetLocaleSymbol(const std::string& symbol);
  void ParseFixSubmitResponse(const FIX::Message& message);
  void ParseFixCancelResponse(const FIX::Message& message);
  void ParseFixFillInfo(const FIX::Message& message);
  void ParseFixOrderInfo(const FIX::Message& message);

  template <class T>
  inline std::optional<int64_t> ToInt64(T&& val) const {
    try {
      return stoll(val);
    } catch (std::exception& ex) {
      return {};
    }
  }
  inline std::string ExtractFillID(const std::string& exec_id) const {
    if (auto pos = exec_id.find('|'); pos != std::string::npos) {
      return exec_id.substr(0, pos);
    }
    return exec_id;
  }

 private:
  coin::proto::OrderEvent order_event_;
  std::map<std::string, std::string> fix_native_map_;
  bool is_account_balance_initialized_ = false;
};

}  // namespace coin2::exchange::bitstamp::order_v2
